using System;
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using Google.Protobuf;

public class CharacterController : MonoBehaviour, IPointerClickHandler, IDragHandler, IBeginDragHandler, IEndDragHandler
{
    public Character character;
    public FSMStateController stateController;

    void Start()
    {
        character = GetComponent<Character>();
        stateController = new FSMStateController(character);
        stateController.SetState<IdleState>();

        character.speedMultiplier = GameSetting.Instance.settingData.speed;
        character.SetScaleMultiplier(GameSetting.Instance.settingData.size);
    
        transform.FindChildEx("InputCounter").gameObject.AddComponent<InputCounter>();

        EventMgr.Instance.RegisterEvent(EventType.SpeedChanged, OnSpeedChanged);
        EventMgr.Instance.RegisterEvent(EventType.ScaleChanged, OnScaleChanged);
        EventMgr.Instance.RegisterEvent(EventType.SwitchMonotor, OnSwitchMonitor);

        StartCoroutine(SendSyncState());
    }

    void OnDestroy()
    {
        EventMgr.Instance.RemoveEvent(EventType.SpeedChanged, OnSpeedChanged);
        EventMgr.Instance.RemoveEvent(EventType.ScaleChanged, OnScaleChanged);
        EventMgr.Instance.RemoveEvent(EventType.SwitchMonotor, OnSwitchMonitor);
    }

    void Update()
    {
        var dt = Time.deltaTime;
        stateController.UpdateState(dt);
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        if (!eventData.dragging)
        {
            int index = UnityEngine.Random.Range(1, 20);
            CV cv = GameSetting.Instance.settingData.cv;
            if (cv == CV.Random)
            {
                cv = (CV)UnityEngine.Random.Range(0, (int)CV.Count);
            }
            string audioIndex = GameManager.cvMap[cv];
            string name = $"vo_{audioIndex}_000_{index:D3}_0";
            GameManager.Instance.PlayAudio(name);

            EventMgr.Instance.SendEvent(EventType.ChracterClicked);
        }
        if ( eventData.button == PointerEventData.InputButton.Right)
        {
            UIMgr.Instance.Open<UIMainPanel>();
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        this.GetComponent<RectTransform>().anchoredPosition += eventData.delta;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        character.isDragging = true;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        character.isDragging = false;
    }

    private void OnSpeedChanged(Message msg){
        character.speedMultiplier = GameSetting.Instance.settingData.speed;
    }
    
    private void OnScaleChanged(Message msg){
        character.SetScaleMultiplier(GameSetting.Instance.settingData.size);
    }

    private void OnSwitchMonitor(Message msg)
    {
        character.rootTrans.anchoredPosition = new Vector2(0, 200);
    }

    private IEnumerator SendSyncState()
    {
        while (true)
        {
            if (TCPClient.Instance.isLogin && TCPClient.Instance.IsConnected())
            {
                TCPClient.Instance.SendMessage(NetMsgID.CsSyncState, new CS_SyncState{
                    Pos = new Vector2f {X = character.GetPosition().x, Y = character.GetPosition().y},
                    Scale = new Vector2f {X = character.GetScale().x, Y = character.GetScale().y},
                    Anim = (int)character.state,
                    Count = GlobalKeyboardListener.Instance.totalClickCount,
                });   
            }
            yield return new WaitForSecondsRealtime(0.2f);
        }
    }
}


public class IdleState : FSMStateBase
{
    public IdleState(FSMStateController stateController) : base(stateController) { }

    public override void Enter()
    {
        EventMgr.Instance.RegisterEvent(EventType.ChracterClicked, this.OnClicked);
        GlobalKeyboardListener.Instance.AddKeyDownHandler(OnGlobalKeyDown);
        stateController.character.SetState(CharacterState.Idle);
    }

    public override void Exit()
    {
        EventMgr.Instance.RemoveEvent(EventType.ChracterClicked, this.OnClicked);
        GlobalKeyboardListener.Instance.RemoveKeyDownHandler(OnGlobalKeyDown);
    }

    public override void Update(float dt)
    {
        var character = stateController.character;
        character.energy = Mathf.Clamp(character.energy - dt * 0.5f, 0, character.maxEnergy);
        if (character.energy > 10f)
        {
            stateController.SetState<WakeUpState>();
        }
    }

    private void OnClicked(Message msg)
    {
        stateController.SetState<WakeUpState>();
    }

    private void OnGlobalKeyDown(Keys key)
    {
        stateController.character.energy = Mathf.Clamp(stateController.character.energy + 1, 0, stateController.character.maxEnergy);
    }
}

public class WakeUpState : FSMStateBase
{
    public WakeUpState(FSMStateController stateController) : base(stateController) { }

    public override void Enter()
    {
        stateController.character.SetState(CharacterState.WakeUp);
    }

    public override void Update(float dt)
    {
        if (timer > 1.5f)
        {
            stateController.SetState<MoveState>();
        }
    }
}

public class MoveState : FSMStateBase
{
    public MoveState(FSMStateController stateController) : base(stateController) { }

    public override void Enter()
    {
        stateController.character.energy = 20;
        stateController.character.SetState(CharacterState.Move);
        GlobalKeyboardListener.Instance.AddKeyDownHandler(OnGlobalKeyDown);
    }

    public override void Exit()
    {
        GlobalKeyboardListener.Instance.RemoveKeyDownHandler(OnGlobalKeyDown);
    }

    public override void Update(float dt)
    {
        var character = stateController.character;

        character.energy = Mathf.Clamp(character.energy - dt, 0, character.maxEnergy);
        character.Move(dt);

        if(character.energy <= 0 && !GameSetting.Instance.settingData.neverSleep)
        {
            stateController.SetState<SleepState>();
        }
    }

    private void OnGlobalKeyDown(Keys key)
    {
        stateController.character.energy = Mathf.Clamp(stateController.character.energy + 2, 0, stateController.character.maxEnergy);
    }
}

public class SleepState : FSMStateBase
{
    public SleepState(FSMStateController stateController) : base(stateController) { }

    public override void Enter()
    {
        stateController.character.SetState(CharacterState.Sleep);
        EventMgr.Instance.RegisterEvent(EventType.ChracterClicked, this.OnClicked);
    }
    public override void Exit()
    {
        EventMgr.Instance.RemoveEvent(EventType.ChracterClicked, this.OnClicked);
    }

    private void OnClicked(Message msg)
    {
        stateController.SetState<MoveState>();
    }

    public override void Update(float dt)
    {
        if (timer > 30f)
        {
            stateController.SetState<IdleState>();
        }
    }
}
